﻿Option Strict On

Imports System.Collections.Generic
Imports System.Text
Imports System.Globalization
Imports SFDL.FTP.FTP.Exceptions

Namespace FTP
    ''' <summary>
    ''' FTP request object which contains the command, arguments and text or an FTP request.
    ''' </summary>
    Public Class FtpRequest
        Private _command As FtpCmd
        Private _arguments As String()
        Private _text As String
        Private _encoding As Encoding

        ''' <summary>
        ''' Default constructor.
        ''' </summary>
        Public Sub New()
            _encoding = Encoding.UTF8
            _command = New FtpCmd()
            _text = String.Empty
        End Sub

        ''' <summary>
        ''' FTP request constructor.
        ''' </summary>
        ''' <param name="encoding">Text encoding object to use.</param>
        ''' <param name="command">FTP request command.</param>
        ''' <param name="arguments">Parameters for the request</param>
        Friend Sub New(ByVal encoding As Encoding, ByVal command As FtpCmd, ByVal ParamArray arguments As String())
            _encoding = encoding
            _command = command
            _arguments = arguments
            _text = BuildCommandText()
        End Sub

        ''' <summary>
        ''' FTP request constructor.
        ''' </summary>
        ''' <param name="encoding">Text encoding object to use.</param>
        ''' <param name="command">FTP request command.</param>
        Friend Sub New(ByVal encoding As Encoding, ByVal command As FtpCmd)
            Me.New(encoding, command, Nothing)
        End Sub

        ''' <summary>
        ''' Get the FTP command enumeration value.
        ''' </summary>
        Public ReadOnly Property Command() As FtpCmd
            Get
                Return _command
            End Get
        End Property

        ''' <summary>
        ''' Get the FTP command arguments (if any).
        ''' </summary>
        Public ReadOnly Property Arguments() As List(Of String)
            Get
                Return New List(Of String)(_arguments)
            End Get
        End Property

        ''' <summary>
        ''' Get the FTP command text with any arguments.
        ''' </summary>
        Public ReadOnly Property Text() As String
            Get
                Return _text
            End Get
        End Property

        ''' <summary>
        ''' Gets a boolean value indicating if the command is a file transfer or not.
        ''' </summary>
        Public ReadOnly Property IsFileTransfer() As Boolean
            Get
                If _command = FtpCmd.Stou OrElse _command = FtpCmd.Stor OrElse _command = FtpCmd.Retr Then
                    Return True
                Else
                    Return False
                End If
            End Get
        End Property

        Friend Function BuildCommandText() As String
            Dim commandText As String = _command.ToString().ToUpper(CultureInfo.InvariantCulture)

            If _arguments Is Nothing Then
                Return commandText
            Else
                Dim builder As New StringBuilder()
                For Each arg As String In _arguments
                    builder.Append(arg)
                    builder.Append(" ")
                Next
                Dim argText As String = builder.ToString().Trim()

                If _command = FtpCmd.Unknown Then
                    Return argText
                Else
                    Return String.Format("{0} {1}", commandText, argText).TrimEnd()
                End If
            End If
        End Function

        Friend Function GetBytes() As Byte()
            Return _encoding.GetBytes(String.Format("{0}" & vbCr & vbLf, _text))
        End Function

        Friend ReadOnly Property HasHappyCodes() As Boolean
            Get
                Return If(GetHappyCodes().Length = 0, False, True)
            End Get
        End Property


        Friend Function GetHappyCodes() As FtpResponseCode()
            Select Case _command
                Case FtpCmd.Unknown
                    Return BuildResponseArray()
                Case FtpCmd.Allo
                    Return BuildResponseArray(FtpResponseCode.CommandOkay, FtpResponseCode.CommandNotImplementedSuperfluousAtThisSite)
                Case FtpCmd.User
                    Return BuildResponseArray(FtpResponseCode.UserNameOkayButNeedPassword, FtpResponseCode.ServiceReadyForNewUser, FtpResponseCode.UserLoggedIn)
                Case FtpCmd.Pass
                    Return BuildResponseArray(FtpResponseCode.UserLoggedIn, FtpResponseCode.ServiceReadyForNewUser, FtpResponseCode.NotLoggedIn)
                Case FtpCmd.Cwd
                    Return BuildResponseArray(FtpResponseCode.RequestedFileActionOkayAndCompleted)
                Case FtpCmd.Pwd
                    Return BuildResponseArray(FtpResponseCode.PathNameCreated)
                Case FtpCmd.Dele
                    Return BuildResponseArray(FtpResponseCode.RequestedFileActionOkayAndCompleted)
                Case FtpCmd.Abor
                    Return BuildResponseArray()
                Case FtpCmd.Mkd
                    Return BuildResponseArray(FtpResponseCode.PathNameCreated)
                Case FtpCmd.Rmd
                    Return BuildResponseArray(FtpResponseCode.RequestedFileActionOkayAndCompleted)
                Case FtpCmd.Help
                    Return BuildResponseArray(FtpResponseCode.SystemStatusOrHelpReply, FtpResponseCode.HelpMessage, FtpResponseCode.FileStatus)
                Case FtpCmd.Mdtm
                    Return BuildResponseArray(FtpResponseCode.FileStatus)
                Case FtpCmd.Stat
                    Return BuildResponseArray(FtpResponseCode.SystemStatusOrHelpReply, FtpResponseCode.DirectoryStatus, FtpResponseCode.FileStatus)
                Case FtpCmd.Cdup
                    Return BuildResponseArray(FtpResponseCode.CommandOkay, FtpResponseCode.RequestedFileActionOkayAndCompleted)
                Case FtpCmd.Size
                    Return BuildResponseArray(FtpResponseCode.FileStatus)
                Case FtpCmd.Feat
                    Return BuildResponseArray(FtpResponseCode.SystemStatusOrHelpReply)
                Case FtpCmd.Syst
                    Return BuildResponseArray(FtpResponseCode.NameSystemType)
                Case FtpCmd.Rnfr
                    Return BuildResponseArray(FtpResponseCode.RequestedFileActionPendingFurtherInformation)
                Case FtpCmd.Rnto
                    Return BuildResponseArray(FtpResponseCode.RequestedFileActionOkayAndCompleted)
                Case FtpCmd.Noop
                    Return BuildResponseArray(FtpResponseCode.CommandOkay)
                Case FtpCmd.Site
                    Return BuildResponseArray(FtpResponseCode.CommandOkay, FtpResponseCode.CommandNotImplementedSuperfluousAtThisSite, FtpResponseCode.RequestedFileActionOkayAndCompleted)
                Case FtpCmd.Pasv
                    Return BuildResponseArray(FtpResponseCode.EnteringPassiveMode)
                Case FtpCmd.Port
                    Return BuildResponseArray(FtpResponseCode.CommandOkay)
                Case FtpCmd.Type
                    Return BuildResponseArray(FtpResponseCode.CommandOkay)
                Case FtpCmd.Rest
                    Return BuildResponseArray(FtpResponseCode.RequestedFileActionPendingFurtherInformation)
                Case FtpCmd.Mode
                    Return BuildResponseArray(FtpResponseCode.CommandOkay)
                Case FtpCmd.Quit
                    Return BuildResponseArray()
                Case FtpCmd.Auth
                    Return BuildResponseArray(FtpResponseCode.AuthenticationCommandOkay)
                Case FtpCmd.Pbsz
                    Return BuildResponseArray(FtpResponseCode.CommandOkay)
                Case FtpCmd.Prot
                    Return BuildResponseArray(FtpResponseCode.CommandOkay)
                Case FtpCmd.List, FtpCmd.Nlst
                    Return BuildResponseArray(FtpResponseCode.DataConnectionAlreadyOpenSoTransferStarting, FtpResponseCode.FileStatusOkaySoAboutToOpenDataConnection, FtpResponseCode.ClosingDataConnection, FtpResponseCode.RequestedFileActionOkayAndCompleted)
                Case FtpCmd.Appe, FtpCmd.Stor, FtpCmd.Stou, FtpCmd.Retr
                    Return BuildResponseArray(FtpResponseCode.DataConnectionAlreadyOpenSoTransferStarting, FtpResponseCode.FileStatusOkaySoAboutToOpenDataConnection, FtpResponseCode.ClosingDataConnection, FtpResponseCode.RequestedFileActionOkayAndCompleted)
                Case FtpCmd.Xcrc, FtpCmd.Xmd5, FtpCmd.Xsha1
                    Return BuildResponseArray(FtpResponseCode.RequestedFileActionOkayAndCompleted)
                Case FtpCmd.Epsv
                    Return BuildResponseArray()
                Case FtpCmd.Erpt
                    Return BuildResponseArray()
                Case Else

                    Throw New FtpException(String.Format("No response code(s) defined for FtpCmd {0}.", _command.ToString()))
            End Select
        End Function

        Private Function BuildResponseArray(ByVal ParamArray codes As FtpResponseCode()) As FtpResponseCode()
            Return codes
        End Function

    End Class
End Namespace